#include <func.h>
#include "head.h"
int makeMd5(char *filename, char **md){
    int fd = open(filename,O_RDWR);
    ERRMSG_INCLUDED(fd,-1,"open");
    struct stat statbuf;
    fstat(fd,&statbuf);
    char *p = (char *)mmap(NULL,statbuf.st_size,PROT_READ,MAP_SHARED,fd,0);
    unsigned char MD[16];
    MD5((unsigned char *)p,strlen(p),MD);
     sprintf(*md,"%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x",
             MD[0],MD[1],MD[2],MD[3],MD[4],MD[5],MD[6],MD[7],
             MD[8],MD[9],MD[10],MD[11],MD[12],MD[13],MD[14],MD[15]);
}

//在数据库中有多少个文件是该MD5，允许多个不同名字的文件指向同一个文件
int getMd5(char **md,int pre_id,char *fileName){
    //进入对应数据库
    MYSQL *db = mysql_init(NULL);
    char * host = "localhost";
    char * user = "root";
    char * password = "123";
    char * database = "netDisk";
    MYSQL * ret = mysql_real_connect(db,host,user,password,database,0,NULL,0);
    if(ret != 0){
        printf("mysql connect successed\n");
    }
    else{
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    //选择执行语句
    char sql[300] = {0};
    sprintf(sql,"select md5 from fileDir where pre_id = %d and name = '%s'",pre_id,fileName);
    int qret = mysql_query(db,sql);
    if(qret != 0){
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    int num;
    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_ROW  row;
    if((row = mysql_fetch_row(result)) != NULL){
         strcpy(*md,row[0]);
    }
    mysql_free_result(result);
    mysql_close(db);
    return num;
}

int saveFileData(char *filename,char *type,char *username,int pre_id,char *md5){
    //进入对应数据库
    MYSQL *db = mysql_init(NULL);
    char * host = "localhost";
    char * user = "root";
    char * password = "123";
    char * database = "netDisk";
    MYSQL * ret = mysql_real_connect(db,host,user,password,database,0,NULL,0);
    if(ret != 0){
        printf("mysql connect successed\n");
    }
    else{
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    //选择执行语句
    char sql[300] = {0};
    sprintf(sql,"insert into fileDir (name,type,user,pre_id,md5) values ('%s','%s','%s',%d,'%s')"
            ,filename,type,username,pre_id,md5);
    int qret = mysql_query(db,sql);
    if(qret != 0){
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    mysql_close(db);
}

//获取当前用户的最开始的目录，即当前用户的根目录
int getOriginId(char *username){
      //进入对应数据库
    MYSQL *db = mysql_init(NULL);
    char * host = "localhost";
    char * user = "root";
    char * password = "123";
    char * database = "netDisk";
    MYSQL * ret = mysql_real_connect(db,host,user,password,database,0,NULL,0);
    if(ret != 0){
        printf("mysql connect successed\n");
    }
    else{
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    //选择执行语句
    char sql[300] = {0};
    sprintf(sql,"select min(id) from fileDir where user = '%s'",username);
    int qret = mysql_query(db,sql);
    if(qret != 0){
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    int num;
    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_ROW  row;
    if((row = mysql_fetch_row(result)) != NULL){
         num = atoi(row[0]);
    }
    mysql_free_result(result);
    mysql_close(db);
    return num;
}


//进入下一层目录
int cd(char *filename,int pre_id){
    //进入对应数据库
    MYSQL *db = mysql_init(NULL);
    char * host = "localhost";
    char * user = "root";
    char * password = "123";
    char * database = "netDisk";
    MYSQL * ret = mysql_real_connect(db,host,user,password,database,0,NULL,0);
    if(ret != 0){
        printf("mysql connect successed\n");
    }
    else{
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    //选择执行语句
    char sql[300] = {0};
    sprintf(sql,"select id from fileDir where name = '%s' and pre_id = %d",filename,pre_id);
    int qret = mysql_query(db,sql);
    if(qret != 0){
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    int num;
    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_ROW  row;
    if((row = mysql_fetch_row(result)) != NULL){
         num = atoi(row[0]);
    }
    mysql_free_result(result);
    mysql_close(db);
    return num;
}

//服务端获取当前目录底下所有文件的信息，并发送给客户端
int lsSever(int netFd,int pre_id){
        //进入对应数据库
    MYSQL *db = mysql_init(NULL);
    char * host = "localhost";
    char * user = "root";
    char * password = "123";
    char * database = "netDisk";
    MYSQL * ret = mysql_real_connect(db,host,user,password,database,0,NULL,0);
    if(ret != 0){
        printf("successed\n");
    }
    else{
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    //选择执行语句
    char sql[300] = {0};
    sprintf(sql,"select name,type,user from fileDir where pre_id = %d",pre_id);
    int qret = mysql_query(db,sql);
    if(qret != 0){
        printf("error: %s\n",mysql_error(db));
        exit(-1);
    }
    //用sendbuf暂存一下ls的信息，其实也可以直接往t.buf写
    char sendbuf[4096] = {0};
    train_t t;
    bzero(&t,sizeof(t));
    MYSQL_RES *result = mysql_store_result(db);
    MYSQL_ROW  row;
    while((row = mysql_fetch_row(result)) != NULL){
        //sprintf会存在行覆盖行为，因此每次需要重写一次
        //row[0]:filename row[1]:type row[2]:user
        sprintf(sendbuf,"%s   %s   %s\n",row[0],row[1],row[2]);
        strcat(t.buf,sendbuf);
    }
    mysql_free_result(result);
    mysql_close(db);
    t.dataLength = strlen(t.buf);
    //发送ls信息
    send(netFd,&t,sizeof(t.dataLength) + t.dataLength,0);
}

//接收服务端发送过来ls信息，并打印下来
int lsClient(int netFd){
    int dataLength;
    char lsMsg[4096] = {0};
    //接收ls信息
    recv(netFd,&dataLength,sizeof(dataLength),0);
    recv(netFd,lsMsg,dataLength,0);
    //将接收到的信息打印到屏幕上
    puts(lsMsg);
}

int uploadClient(int netFd,char * fileName){
    train_t t;
    bzero(&t,sizeof(t));
    //给服务端发送文件名
    t.dataLength=strlen(fileName);
    strcpy(t.buf,fileName);
    int ret=send(netFd,&t,sizeof(int)+t.dataLength,MSG_NOSIGNAL);
    ERROR_CHECK(ret,-1,"发送服务端被下载文件名字长度+文件名字");
    //生成md5码
    char* md = (char *)calloc(50,sizeof(char));
    makeMd5(fileName,&md);
    //发送md5码
    bzero(&t,sizeof(t));
    t.dataLength = strlen(md);
    strcpy(t.buf,md);
    ret = send(netFd,&t,sizeof(t.dataLength) + t.dataLength,0);
    ERRMSG_INCLUDED(ret,-1,"send");
    //发送文件
    sendFile(fileName,netFd);
    free(md);
}

//pre_id为当前路径，用数据库中的id表示,传进去就上传后该文件的父节点
//username用于后面多客户端连接时，每个用户只能在自己的目录里上传与下载
int uploadSever(int netFd,char *username,int pre_id){
    train_t t;
    bzero(&t,sizeof(t));
    int dataLength;
    //接收文件名
    char filename[50] = {0};
    int ret = recv(netFd,&dataLength,sizeof(dataLength),0);
    ERROR_CHECK(ret,-1,"recv namelen");
    ret = recv(netFd,filename,dataLength,0);
    ERROR_CHECK(ret,-1,"recv name");
    //接收md5码
    char md5[50] = {0};
    ret = recv(netFd,&dataLength,sizeof(dataLength),0);
    ERROR_CHECK(ret,-1,"recv md5len");
    ret = recv(netFd,md5,dataLength,0);
    ERROR_CHECK(ret,-1,"recv md5");
    //将该文件的信息放到数据库fileDir表格中
    saveFileData(filename,"f",username,pre_id,md5);
    //接收文件，并将文件名改为md5码
    recvFile(netFd,md5);
}

//客户端与服务端应同步一个pre_id作为当前路径，然后下载父节点为当前路径pre_id的文件
int downClient(int netFd,char *fileName){
    train_t t;
    //发送文件名，让服务端通过pre_id与fileName找到需要下载文件的md5码，因为服务端文件名为md5码
    bzero(&t,sizeof(t));
    t.dataLength = strlen(fileName);
    strcpy(t.buf,fileName);
    send(netFd,&t,sizeof(t.dataLength) + t.dataLength,0);
    //接收文件
    recvFile(netFd,fileName);
}

//服务端通过接收客户端发送过来的文件名与以及二者同步的pre_id来找到对应文件的md5码，然后传输文件
int downSever(int netFd,int pre_id){
    char filename[50]  = {0};
    char *md5 = (char *)calloc(50,sizeof(char));
    int dataLength;
    //接收文件名
    recv(netFd,&dataLength,sizeof(dataLength),0);
    recv(netFd,filename,dataLength,0);
    //通过文件名与pre_id获取该文件的md5码
    getMd5(&md5,pre_id,filename);
    //发送文件
    sendFile(md5,netFd);
    //使用完记得释放内存，防止内存泄漏
    free(md5);
}